package com.security;

import cn.hutool.core.util.StrUtil;
import com.utils.JwtTokenUtil;
import com.utils.ResponseUtil;
import com.utils.RestResponse;
import com.utils.ResultCode;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import javax.annotation.Resource;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.web.filter.OncePerRequestFilter;

/**
 * @author t-zhaoheng
 * @since 2022/3/30
 */
@Slf4j
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {

  JwtTokenUtil jwtTokenUtil = new JwtTokenUtil();

  String[] permitArr = new String[]{"/biaoqianfenlei/list", "/biaoqianfenlei/detail/**",
      "/option/**/**", "/follow/**/**", "/remind/**/**/**", "/cal/**/**", "/group/**/**",
      "/value/**/**/**", "/value/**/**/**/**", "/matchFace", "/config/list", "/config/detail/**",
      "/discusszhishixinxi/list", "/discusszhishixinxi/detail/**", "file/download", "/news/list",
      "/news/detail/**", "/storeup/detail/**", "/user/login", "/user/register", "/user/resetPass",
      "/xiangmufenlei/list", "/xiangmufenlei/detail/**", "/yonghu/login", "/yonghu/register",
      "/yonghu/resetPass", "/yonghu/page", "/yonghu/list", "/yonghu/detail/**", "/zhishixinxi/list",
      "/zhishixinxi/detail/**", "/zhishixinxi/autoSort", "/matchPassword", "/front/**",
      "/upload/**", "/admin/**", "/error"};

  List<Pattern> patternList = Arrays.stream(permitArr)
      .map(s -> {
        String s1 = s;
        if (s.contains("**")) {
          s1 = s.replaceAll("\\*\\*", "\\\\w+");
        }
        return s1;
      }).map(Pattern::compile).collect(Collectors.toList());

  @Resource
  MyUserDetailsService userDetailsService;

  @Override
  protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,
      FilterChain filterChain) throws ServletException, IOException {
    // 不管是否传了token，只要是不用校验的url，直接放行
    String requestURI = request.getRequestURI();
    boolean match = patternList.stream().anyMatch(pattern ->
        pattern.matcher(requestURI).matches()
    );
    if(match) {
      filterChain.doFilter(request, response);
      return;
    }

    // 如果没有传token，或者传的token为字符串 'null'，直接放行
    String token = request.getHeader("Token");
    if (StrUtil.isEmpty(token) || StrUtil.equalsIgnoreCase(token, "null")) {
      filterChain.doFilter(request, response);
      return;
    }


    // 如果是注册，直接放行
    if (requestURI.contains("register")) {
      filterChain.doFilter(request, response);
      return;
    }
    // 如果用户走的是登录请求
    if (!requestURI.contains("/login")) {
      // 获取请求的token
//      log.info("token:{}", token);
      if (StrUtil.isEmpty(token)) {
        ResponseUtil.writeJson(response, RestResponse.fail(ResultCode.TOKEN_INVALID));
        return;
      }

      // 判断当前token是否过期
      if (jwtTokenUtil.isTokenExpired(token)) {
        ResponseUtil.writeJson(response, RestResponse.fail(ResultCode.TOKEN_EXPIRED));
        return;
      }
      // 解析token，获取用户信息
      String username = jwtTokenUtil.getUsernameFromToken(token);
//      log.info("用户：{}", username);
      // 从内存获取用户的信息
      Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
      // 如果为空，则设置之
      if (authentication == null) {
        UserDetails userDetails = userDetailsService.loadUserByUsername(username);
        authentication = new UsernamePasswordAuthenticationToken(userDetails, null,
            userDetails.getAuthorities());
        SecurityContextHolder.getContext().setAuthentication(authentication);
      }

    }

    filterChain.doFilter(request, response);
  }

  public static void main(String[] args) {
    String str = "1/**2/**";
    String r = str.replaceAll("\\*\\*", "\\\\w+");
    System.out.println(r);
    Pattern p = Pattern.compile(r);
    boolean matches = p.matcher("1/reeee2/e").matches();
    System.out.println(matches);
  }
}
